/*
版本OpenHarmony3.0
编译环境Docker
AP模式DHCP无法启动，手机手动配置IP可以连接
SAT模式可以连接上手机热点，热点显示未知，IP是空的
*/

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "ohos_types.h"

#include "lwip/sockets.h"
#include "lwip/netif.h"
#include "lwip/netifapi.h"
#include "lwip/ip4_addr.h"
#include "lwip/api_shell.h"

#include "wifi_device.h"
#include "wifi_device_config.h"
#include "wifi_hotspot.h"
#include "wifi_error_code.h"
#include "wifi_event.h"

#include "cJSON.h"

#include "cmsis_os2.h"
#include "iot_gpio.h"

// Mode AP or SAT
#define SAT


//#define WIFI_MAX_STA_NUM 8

static struct netif *g_lwip_netif = NULL;

// WIFI 标志位
#ifdef SAT
static int g_staScanSuccess = 0;
static int g_ConnectSuccess = 0;
static int ssid_count = 0;
#else
static int g_apEnableSuccess = 0;
#endif

WifiErrorCode error;

//WIFI config
#ifdef SAT
#define SELECT_WLAN_PORT "wlan0"
// #define SELECT_WIFI_SSID "OPPO R15"
#define SELECT_WIFI_SSID "HUAWEI Mate 30"
#define SELECT_WIFI_PASSWORD "A0v204n8"
#define SELECT_WIFI_SECURITYTYPE WIFI_SEC_TYPE_PSK
#else
#define AP_SSID "Hi3861_Wifi"
#define AP_PSK  "123456789"
#endif


#define _PROT_ 8888
#define TCP_BACKLOG 10

int sock_fd, new_fd;
char recvbuf[512];
char *buf = "Hello! I'm Hi3861 TCP Server!";

//WIFI init
#ifdef SAT
static void OnWifiScanStateChangedHandler(int state, int size);
static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info);
static void Wifi_SAT_Init(void){
    printf("<--Wifi Init-->\r\n");
    WifiEvent g_wifiEventHandler = {0};
    g_wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedHandler;
    g_wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedHandler;
    error = RegisterWifiEvent(&g_wifiEventHandler);
    if (error != WIFI_SUCCESS)
    {
        printf("[error]register wifi event fail!\r\n");
    }
    else
    {
        printf("[done]register wifi event succeed!\r\n");
    }
}
static int WaitConnectResult(void)
{
    unsigned int time = 0; 
    while (!g_ConnectSuccess)
    {
        osDelay(100);
        time++;
        printf("[outp]wite [%d]\n",time);
    }
    printf("[done]WaitConnectResult:wait success\n");
    return 1;
}
static void PrintLinkedInfo(WifiLinkedInfo* info)
{
    if (!info) return;

    static char macAddress[32] = {0};
    unsigned char* mac = info->bssid;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    printf("bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %s\r\n",
        macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid);
}
static void OnWifiScanStateChangedHandler(int state, int size)
{
    (void)state;
    printf("%s %d, state = %X, size = %d\r\n", __FUNCTION__, __LINE__, state, size);
    if (size > 0)
    {
        ssid_count = size;
        g_staScanSuccess = 1;
    }
    return;
}

static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info)
{
    if (!info) return;

    if (state == WIFI_STATE_AVALIABLE)
    {
        g_ConnectSuccess = 1;
        PrintLinkedInfo(info);
        printf("callback function for wifi connect\r\n");
    }
    else
    {
        printf("connect error,please check password\r\n");
    }
    return;
}
#else
static void OnHotspotStaJoinHandler(StationInfo *info);
static void OnHotspotStateChangedHandler(int state);
static void OnHotspotStaLeaveHandler(StationInfo *info);
static void Wifi_AP_Init(void){
    //注册wifi事件的回调函数
    WifiEvent g_wifiEventHandler = {0};
    g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;
    g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;
    g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;
    error = RegisterWifiEvent(&g_wifiEventHandler);
    if (error != WIFI_SUCCESS)
    {
        printf("[error]RegisterWifiEvent failed, error = %d.\r\n",error);
        return -1;
    }
    printf("[done]RegisterWifiEvent succeed!\r\n");
}
static void HotspotStaJoinTask(void)
{
    static char macAddress[32] = {0};
    StationInfo stainfo[WIFI_MAX_STA_NUM] = {0};
    StationInfo *sta_list_node = NULL;
    unsigned int size = WIFI_MAX_STA_NUM;

    error = GetStationList(stainfo, &size);
    if (error != WIFI_SUCCESS) {
        printf("HotspotStaJoin:get list fail, error is %d.\r\n", error);
        return;
    }
    sta_list_node = stainfo;
    for (uint32_t i = 0; i < size; i++, sta_list_node++) {
    unsigned char* mac = sta_list_node->macAddress;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    printf("HotspotSta[%d]: macAddress=%s.\r\n",i, macAddress);
    }
    g_apEnableSuccess++;
}

static void OnHotspotStaJoinHandler(StationInfo *info)
{
    if (info == NULL) {
    printf("HotspotStaJoin:info is null.\r\n");
    } 
    else {
        printf("New Sta Join\n");
        osThreadAttr_t attr;
        attr.name = "HotspotStaJoinTask";
        attr.attr_bits = 0U;
        attr.cb_mem = NULL;
        attr.cb_size = 0U;
        attr.stack_mem = NULL;
        attr.stack_size = 2048;
        attr.priority = 24;
        if (osThreadNew((osThreadFunc_t)HotspotStaJoinTask, NULL, &attr) == NULL) {
            printf("HotspotStaJoin:create task fail!\r\n");
        }
    }
    return;
}

static void OnHotspotStaLeaveHandler(StationInfo *info)
{
    if (info == NULL) {
        printf("HotspotStaLeave:info is null.\r\n");
    } 
    else {
        static char macAddress[32] = {0};
        unsigned char* mac = info->macAddress;
        snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
        printf("HotspotStaLeave: macAddress=%s, reason=%d.\r\n", macAddress, info->disconnectedReason);
        g_apEnableSuccess--;
    }
    return;
}

static void OnHotspotStateChangedHandler(int state)
{
    printf("HotspotStateChanged:state is %d.\r\n", state);
    if (state == WIFI_HOTSPOT_ACTIVE) {
        printf("wifi hotspot active.\r\n");
    } else {
        printf("wifi hotspot noactive.\r\n");
    }
}
#endif

//Wifi connetc
#ifdef SAT
//Not OK
static int WifiSTAConnect(void)
{
    WifiDeviceConfig select_ap_config = {0};

    osDelay(200);
    printf("<------System Init------>\r\n");

    //初始化WIFI
    Wifi_SAT_Init();
    osDelay(100);
    //使能WIFI
    if (EnableWifi() != WIFI_SUCCESS)
    {
        printf("[error]EnableWifi failed, error = %d\n", error);
        return -1;
    }
    else{
        printf("[done]EnableWifi is success\n");
    }

    //判断WIFI是否激活
    if (IsWifiActive() == 0)
    {
        printf("[error]Wifi station is not actived.\n");
        return -1;
    }
    else{
        printf("[done]Wifi is activing\n");
    }
    
    //拷贝要连接的热点信息
    strcpy(select_ap_config.ssid, SELECT_WIFI_SSID);
    strcpy(select_ap_config.preSharedKey, SELECT_WIFI_PASSWORD);
    select_ap_config.securityType = SELECT_WIFI_SECURITYTYPE;
    int result = -1;
    WifiErrorCode rec = AddDeviceConfig(&select_ap_config, &result);
    printf("[outp]AddDeviceConfig rec code: %d\n",rec);
    if (rec == WIFI_SUCCESS)
    {
        printf("[inti]start connect wifi\n");
        rec = ConnectTo(result);
        printf("[outp]ConnectTo rec code: %d ,ID;%d\n",rec,result);
        int re = WaitConnectResult();
        printf("[outp]WaitConnectResult re code: %d\n",re);
        if (rec == WIFI_SUCCESS && re == 1)
        {
            printf("[done]WiFi connect succeed!\r\n");
            g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);
            printf("[outp]g_lwip_netif: %d\n", g_lwip_netif == NULL );
            //启动DHCP
            if (g_lwip_netif)
            {
                dhcp_start(g_lwip_netif);
                printf("[done]begain to dhcp\n");
                for(;;)
                {
                    err_t ret = dhcp_is_bound(g_lwip_netif);
                    if(ret == ERR_OK)
                    {
                        printf("<-- DHCP state:OK -->\r\n");
                        // ip4_addr_t ipAddr;
                        // ret = netifapi_netif_get_addr(g_lwip_netif, &ipAddr, NULL, NULL);
                        // printf("netifapi_netif_get_addr: %d\r\n", ret);
                        // if (ret == 0) {
                        //     printf("IP: %s \n",ip4addr_ntoa(&ipAddr));
                        // }
                        //打印获取到的IP信息
                        netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL);
                        break;
                    }
                    printf("<-- DHCP state:Inprogress -->\r\n");
                    printf("[outp]dhcp_is_bound: %d\r\n", ret);
                    osDelay(100);
                }
            }
        }
    }

    return 0;
}
#else 
static int WifiCreateHotSpot(void){
    HotspotConfig config = {0};

    strcpy(config.ssid, AP_SSID);
    strcpy(config.preSharedKey, AP_PSK);
    config.securityType = WIFI_SEC_TYPE_PSK;
    config.band = HOTSPOT_BAND_TYPE_2G;
    config.channelNum = 7;

    error = SetHotspotConfig(&config);
    if (error != WIFI_SUCCESS)
    {
        printf("[error]SetHotspotConfig failed, error = %d.\r\n", error);
        return -1;
    }
    printf("[done]SetHotspotConfig succeed!\r\n");

    //启动wifi热点模式
    error = EnableHotspot(); 
    if (error != WIFI_SUCCESS)
    {
        printf("[error]EnableHotspot failed, error = %d.\r\n", error);
        return -1;
    }
    printf("[done]EnableHotspot succeed!\r\n");

    //检查热点模式是否使能
    if (IsHotspotActive() == WIFI_HOTSPOT_NOT_ACTIVE)
    {
        printf("[error]Wifi station is not actived.\r\n");
        return -1;
    }
    printf("[done]Wifi station is actived!\r\n");

    //启动dhcp
    g_lwip_netif = netifapi_netif_find("ap0");
    if (g_lwip_netif) 
    {
        ip4_addr_t bp_gw;
        ip4_addr_t bp_ipaddr;
        ip4_addr_t bp_netmask;

        IP4_ADDR(&bp_gw, 192, 168, 1, 1);           /* input your gateway for example: 192.168.1.1 */
        IP4_ADDR(&bp_ipaddr, 192, 168, 1, 1);       /* input your IP for example: 192.168.1.1 */
        IP4_ADDR(&bp_netmask, 255, 255, 255, 0);    /* input your netmask for example: 255.255.255.0 */

        err_t ret = netifapi_netif_set_addr(g_lwip_netif, &bp_ipaddr, &bp_netmask, &bp_gw);
        if(ret != ERR_OK)
        {
            printf("[error]netifapi_netif_set_addr failed, error = %d.\r\n", ret);
            return -1;
        }
        printf("[done]netifapi_netif_set_addr succeed!\r\n");

        ret = netifapi_dhcps_start(g_lwip_netif, 0, 0);
        if(ret != ERR_OK)
        { 
            printf("[error]netifapi_dhcp_start failed, error = %d.\r\n", ret);
            return -1;
        }
        printf("[done]netifapi_dhcps_start succeed!\r\n");
    }
    return 1;
}
#endif

//APP run
static BOOL AppTask(void){
    osDelay(200);
    printf("[init]APP weill started");
    // //服务端地址信息
	// struct sockaddr_in server_sock;

	// //客户端地址信息
	// struct sockaddr_in client_sock;
	// int sin_size;

	// struct sockaddr_in *cli_addr;

#ifdef SAT
    if( WifiSTAConnect() == -1 ){
        printf("[error]wifi connect fail\n");
        return -1;
    }
#else
    if( WifiCreateHotSpot() == -1 ){
        printf("[error]wifi create hotspot fail\n");
        return -1;
    }
#endif
    
    // //创建socket
	// if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	// {
	// 	perror("socket is error\r\n");
	// 	exit(1);
	// }

	// bzero(&server_sock, sizeof(server_sock));
	// server_sock.sin_family = AF_INET;
	// server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
	// server_sock.sin_port = htons(_PROT_);

	// //调用bind函数绑定socket和地址
	// if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
	// {
	// 	perror("bind is error\r\n");
	// 	exit(1);
	// }

	// //调用listen函数监听(指定port监听)
	// if (listen(sock_fd, TCP_BACKLOG) == -1)
	// {
	// 	perror("listen is error\r\n");
	// 	exit(1);
	// }

	// printf("start accept\n");

	// //调用accept函数从队列中
	// for(;;)
	// {
	// 	sin_size = sizeof(struct sockaddr_in);

	// 	if ((new_fd = accept(sock_fd, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
	// 	{
	// 		perror("accept");
	// 		continue;
	// 	}

	// 	cli_addr = malloc(sizeof(struct sockaddr));

	// 	printf("accept addr\r\n");

	// 	if (cli_addr != NULL)
	// 	{
	// 		memcpy(cli_addr, &client_sock, sizeof(struct sockaddr));
	// 	}

	// 	//处理目标
	// 	ssize_t ret;

	// 	while (1)
	// 	{
	// 		if ((ret = recv(new_fd, recvbuf, sizeof(recvbuf), 0)) == -1)
	// 		{
	// 			printf("recv error \r\n");
	// 		}
	// 		printf("recv :%s\r\n", recvbuf);
	// 		sleep(2);
	// 		if ((ret = send(new_fd, buf, strlen(buf) + 1, 0)) == -1)
	// 		{
	// 			perror("send : ");
	// 		}

	// 		sleep(2);
	// 	}

	// 	close(new_fd);
	// }

}


static void Wifi(void)
{
    osThreadAttr_t attr;

    attr.name = "WifiApp";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = 24;
    printf("APP is start...");
    if (osThreadNew((osThreadFunc_t)AppTask, NULL, &attr) == NULL)
    {
        printf("Falied to create WifiSTATask!\n");
    }
}

SYS_RUN(Wifi);
//APP_FEATURE_INIT(WifiClientSTA);